/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年11月21日
 */
package com.massyframework.beanskin.runtime.service.serialize;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.util.Objects;

import com.massyframework.beanskin.ModuleNotFoundException;
import com.massyframework.beanskin.service.metadata.ClassMetadata;
import com.massyframework.beanskin.service.metadata.MetadataRepository;
import com.massyframework.beanskin.service.serialize.MetadataSerializer;
import com.massyframework.beanskin.util.IOUtils;

/**
 * 支持元数据管理的序列化器， 使用于与其他java进程(非massyframework框架进程)进行DTO传输
 * @author huangkh
 *
 */
public final class DefaultMetadataSerailzier  implements MetadataSerializer {

	private final MetadataRepository metadataRepo;
	
	/**
	 * 构造方法
	 */
	public DefaultMetadataSerailzier(MetadataRepository metadataRepo) {
		this.metadataRepo = Objects.requireNonNull(metadataRepo, "\"metadataRepo\" cannot be null.");
	}

	@Override
	public byte[] serial(Object target) throws IOException {
		if (target == null) return new byte[0];
		
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		ObjectOutputStream oos = null;
		try {
			oos = new ObjectOutputStream(os);
			oos.writeObject(target);
			return os.toByteArray();
		}finally {
			if (oos != null) {
				try {
					oos.close();
				}catch(Exception e) {}
			}
			
			try {
				os.close();
			}catch(Exception e) {}
		}
	}

	@Override
	public Object deserial(byte[] bytes) throws IOException, ClassNotFoundException, ModuleNotFoundException {
		if (bytes == null) return null;
		if (bytes.length == 0) return null;
		
		ByteArrayInputStream is = new ByteArrayInputStream(bytes);
		ObjectInputStream ois = null;
		try {
			ois = new ObjectInputStreamExtended(is);
			return ois.readObject();
		}finally {
			IOUtils.close(ois);
			IOUtils.close(is);
		}
	}

	/**
	 * 对象输入流扩展
	 * @author huangkh
	 *
	 */
	private class ObjectInputStreamExtended extends ObjectInputStream {
		
		private ClassLoader classLoader;

		public ObjectInputStreamExtended(InputStream in) throws IOException {
			super(in);
		}

		@Override
		protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
			Class<?> result = null;
			String className = desc.getName();
			if (this.classLoader == null) {
				//首次解析类,使用类名和superType在MetadataRepository中查找
				ClassMetadata metadata = metadataRepo.findClassMetadata(className);
				result = metadata.getOriginal();
				this.classLoader = result.getClassLoader();
			}else {
				//可能解析类包含的嵌套类，或者父类
				result = this.classLoader.loadClass(className);
			}
			
			return result;
		}
	}

}
